"""
工具调用器

负责解析 AI 响应中的工具调用并执行。
"""

import json
import re
from typing import Dict, List, Any, Optional, Tuple

from rich.console import Console

from ..tools import ToolManager, ToolResult

console = Console()


class ToolCaller:
    """工具调用器"""
    
    def __init__(self, tool_manager: ToolManager):
        """
        初始化工具调用器
        
        Args:
            tool_manager: 工具管理器实例
        """
        self.tool_manager = tool_manager
        self.call_history: List[Dict[str, Any]] = []
    
    def extract_tool_calls(self, ai_response: str) -> List[Dict[str, Any]]:
        """
        从 AI 响应中提取工具调用
        
        Args:
            ai_response: AI 的响应文本
            
        Returns:
            List[Dict[str, Any]]: 工具调用列表
        """
        tool_calls = []
        
        # 尝试解析 JSON 格式的工具调用
        json_calls = self._extract_json_tool_calls(ai_response)
        if json_calls:
            tool_calls.extend(json_calls)
        
        # 尝试解析自然语言中的工具调用
        natural_calls = self._extract_natural_tool_calls(ai_response)
        if natural_calls:
            tool_calls.extend(natural_calls)
        
        return tool_calls
    
    def _extract_json_tool_calls(self, text: str) -> List[Dict[str, Any]]:
        """提取 JSON 格式的工具调用"""
        tool_calls = []
        
        # 查找 JSON 代码块
        json_pattern = r'```json\s*(\{.*?\})\s*```'
        matches = re.findall(json_pattern, text, re.DOTALL)
        
        for match in matches:
            try:
                data = json.loads(match)
                if 'tool_calls' in data:
                    for call in data['tool_calls']:
                        if self._validate_tool_call(call):
                            tool_calls.append(call)
            except json.JSONDecodeError:
                continue
        
        # 查找内联 JSON
        inline_json_pattern = r'\{[^{}]*"tool_calls"[^{}]*\}'
        inline_matches = re.findall(inline_json_pattern, text)
        
        for match in inline_matches:
            try:
                data = json.loads(match)
                if 'tool_calls' in data:
                    for call in data['tool_calls']:
                        if self._validate_tool_call(call):
                            tool_calls.append(call)
            except json.JSONDecodeError:
                continue
        
        return tool_calls
    
    def _extract_natural_tool_calls(self, text: str) -> List[Dict[str, Any]]:
        """提取自然语言中的工具调用"""
        tool_calls = []
        
        # 查找 "使用工具" 或 "调用工具" 的模式
        patterns = [
            r'使用\s+(\w+)\s+工具',
            r'调用\s+(\w+)\s+工具',
            r'执行\s+(\w+)\s+工具',
            r'运行\s+(\w+)\s+工具'
        ]
        
        for pattern in patterns:
            matches = re.findall(pattern, text, re.IGNORECASE)
            for tool_name in matches:
                # 尝试从上下文中提取参数
                params = self._extract_parameters_from_context(text, tool_name)
                tool_calls.append({
                    'tool_name': tool_name,
                    'parameters': params,
                    'reason': f'从自然语言中识别到需要调用 {tool_name} 工具'
                })
        
        return tool_calls
    
    def _extract_parameters_from_context(self, text: str, tool_name: str) -> Dict[str, Any]:
        """从上下文中提取工具参数"""
        params = {}
        
        # 根据工具名称提取常见参数
        if tool_name in ['file_search', 'search']:
            # 提取搜索模式
            pattern_match = re.search(r'搜索\s*["\']([^"\']+)["\']', text)
            if pattern_match:
                params['pattern'] = pattern_match.group(1)
            
            # 提取文件类型
            type_match = re.search(r'\.(\w+)', text)
            if type_match:
                params['file_types'] = [f'.{type_match.group(1)}']
        
        elif tool_name in ['code_search']:
            # 提取搜索查询
            query_match = re.search(r'搜索\s*["\']([^"\']+)["\']', text)
            if query_match:
                params['query'] = query_match.group(1)
        
        elif tool_name in ['project_analyzer', 'project']:
            # 项目分析通常不需要额外参数
            params = {}
        
        return params
    
    def _validate_tool_call(self, call: Dict[str, Any]) -> bool:
        """验证工具调用格式"""
        required_fields = ['tool_name']
        return all(field in call for field in required_fields)
    
    def execute_tool_calls(self, tool_calls: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """
        执行工具调用
        
        Args:
            tool_calls: 工具调用列表
            
        Returns:
            List[Dict[str, Any]]: 执行结果列表
        """
        results = []
        
        for call in tool_calls:
            tool_name = call.get('tool_name')
            parameters = call.get('parameters', {})
            reason = call.get('reason', '')
            
            console.print(f"[blue]🔧 调用工具: {tool_name}[/blue]")
            if reason:
                console.print(f"[dim]原因: {reason}[/dim]")
            
            try:
                # 执行工具
                result = self.tool_manager.execute_tool(tool_name, **parameters)
                
                # 记录调用历史
                call_record = {
                    'tool_name': tool_name,
                    'parameters': parameters,
                    'reason': reason,
                    'result': result.to_dict(),
                    'success': result.success
                }
                self.call_history.append(call_record)
                
                results.append(call_record)
                
                if result.success:
                    console.print(f"[green]✓ 工具执行成功[/green]")
                    if result.message:
                        console.print(f"[dim]{result.message}[/dim]")
                else:
                    console.print(f"[red]✗ 工具执行失败: {result.error}[/red]")
                
            except Exception as e:
                console.print(f"[red]✗ 工具执行异常: {e}[/red]")
                
                # 记录失败的调用
                call_record = {
                    'tool_name': tool_name,
                    'parameters': parameters,
                    'reason': reason,
                    'result': {'error': str(e)},
                    'success': False
                }
                self.call_history.append(call_record)
                results.append(call_record)
        
        return results
    
    def get_call_summary(self) -> str:
        """获取调用历史摘要"""
        if not self.call_history:
            return "没有工具调用历史"
        
        summary = f"工具调用历史 ({len(self.call_history)} 次):\n"
        for i, call in enumerate(self.call_history, 1):
            status = "✓" if call['success'] else "✗"
            summary += f"  {i}. {status} {call['tool_name']}"
            if call.get('reason'):
                summary += f" - {call['reason']}"
            summary += "\n"
        
        return summary
    
    def clear_history(self) -> None:
        """清空调用历史"""
        self.call_history.clear()
        console.print("[yellow]工具调用历史已清空[/yellow]")
    
    def suggest_tools_for_query(self, query: str) -> List[str]:
        """根据查询建议合适的工具"""
        suggestions = []
        query_lower = query.lower()
        
        # 文件搜索相关
        if any(word in query_lower for word in ['搜索', '查找', '找', '文件']):
            suggestions.append('file_search')
        
        # 代码搜索相关
        if any(word in query_lower for word in ['代码', '函数', '类', '方法', 'def', 'class']):
            suggestions.append('code_search')
        
        # 项目分析相关
        if any(word in query_lower for word in ['项目', '结构', '分析', '目录']):
            suggestions.append('project_analyzer')
        
        # Git 相关
        if any(word in query_lower for word in ['git', '提交', '状态', '差异', '日志']):
            suggestions.extend(['git_status', 'git_diff', 'git_log'])
        
        # 代码质量相关
        if any(word in query_lower for word in ['质量', '分析', '检查', '问题']):
            suggestions.append('code_quality')
        
        # 依赖相关
        if any(word in query_lower for word in ['依赖', '包', 'requirements', 'package']):
            suggestions.append('dependency_analyzer')
        
        return list(set(suggestions))  # 去重
